use std::ffi::CStr;
use chrono::{DateTime, Local};
use serde::de;
use sqlite_wasm_rs::{sqlite3_column_double, sqlite3_column_int, sqlite3_column_int64, sqlite3_column_text, sqlite3_stmt};
use crate::util::time::{parse_to_time, parse_to_time_m};

pub unsafe fn db_get_int(stmt: *mut sqlite3_stmt, col: i32) -> i32 {
    sqlite3_column_int(stmt, col)
}

pub unsafe fn db_get_int64(stmt: *mut sqlite3_stmt, col: i32) -> u64 {
    sqlite3_column_int64(stmt, col).cast_unsigned()
}

pub unsafe fn db_get_string(stmt: *mut sqlite3_stmt, col: i32) -> Option<String> {
    let value = sqlite3_column_text(stmt, col);
    if value.is_null() {
        None
    } else {
        Some(CStr::from_ptr(value.cast()).to_string_lossy().into_owned())
    }
}

pub unsafe fn db_get_double(stmt: *mut sqlite3_stmt, col: i32) -> f64 {
    sqlite3_column_double(stmt, col)
}

pub unsafe fn db_get_bool(stmt: *mut sqlite3_stmt, col: i32) -> bool {
    sqlite3_column_int(stmt, col) == 1
}

pub unsafe fn db_get_enum<T: for<'a> de::Deserialize<'a>>(stmt: *mut sqlite3_stmt, col: i32) -> T {
    let value = sqlite3_column_int(stmt, col);
    log::info!("enum value: {}, {}", value, col);
    serde_json::from_str(value.to_string().as_str()).unwrap()
}

pub unsafe fn db_get_option_enum<T: for<'a> de::Deserialize<'a>>(stmt: *mut sqlite3_stmt, col: i32) -> Option<T> {
    let value = db_get_string(stmt, col);
    match value {
        None => { None}
        Some(_) => {
            let value = sqlite3_column_int(stmt, col);

            serde_json::from_str(value.to_string().as_str()).unwrap()
        }
    }
}

pub unsafe fn db_get_time(stmt: *mut sqlite3_stmt, col: i32)-> DateTime<Local> {
    let value = db_get_string(stmt, col).unwrap();
    log::info!("db_get_time value: {}, {}", value, col);
    parse_to_time(value)
}

pub unsafe fn db_get_option_date(stmt: *mut sqlite3_stmt, col: i32)-> Option<DateTime<Local>> {
    let value = db_get_string(stmt, col);
    if value.is_none() {
        None
    } else {
        Some(parse_to_time(value.unwrap()))
    }
}

pub unsafe fn db_get_option_date_m(stmt: *mut sqlite3_stmt, col: i32)-> Option<DateTime<Local>> {
    let value = db_get_string(stmt, col);
    if value.is_none() {
        None
    } else {
        Some(parse_to_time_m(value.unwrap()))
    }
}